home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / TextReaderExample ƒ / statsProcs.p < prev   
Encoding:
Text File  |  1993-12-11  |  8.2 KB  |  332 lines  |  [TEXT/PJMM]

  1. { This file is a modified version of the file noCommentsProcs.p that illustrates }
  2. { writing a fairly simple application with MacStarter_pascal.  It also illustrates }
  3. { some other useful stuff, which is commented below. }
  4.  
  5. { This file uses a different resource file from the generic.π project; the file menu }
  6. { contains only a Quit command. }
  7.  
  8. unit applicationProcs;
  9.  
  10. interface
  11.  
  12. uses
  13.     xWindow, xControlDecoration, xTextWindow, TextReader;
  14.    { the TextReader unit difines a class that provides easy accesss to }
  15.    { the text in a TextWindow. }
  16.  
  17.  
  18. const
  19.  
  20.     maxSleepTime = 5;
  21.     ApplicationShortName = 'Simple Stats';
  22.     ApplicationLongName = 'Simple Stats';
  23.     AuthorName = 'David Eck';
  24.     AuthorAddress1 = 'Hobart and William Smith Colleges';
  25.     AuthorAddress2 = 'Geneva, NY   14456';
  26.     AuthorAddress3 = '(Email Address:   eck@hws.BITNET)';
  27.     CommentLine = 'Displays basic statistics for a list of numbers entered by user.';
  28.  
  29.  
  30.  
  31. var
  32.     editMenu: MenuHandle;
  33.     fileMenu: MenuHandle;
  34.  
  35.  
  36. procedure InitializeApplication;
  37. procedure CleanUpApplication;
  38. procedure DoEditMenu (itemNum: integer);
  39. procedure DoFileMenu (itemNum: integer;
  40.                             var done: boolean);
  41. procedure DoOtherMenu (menuNum, itemNum: integer);
  42. procedure UpdateMenus;
  43. procedure ApplicationIdle;
  44.  
  45.  
  46. implementation
  47.  
  48.  
  49. type
  50.  
  51.     myButton = object(xButton)
  52.             procedure HandleClick;
  53.             override;
  54.         end;
  55.  
  56.     myWin = object(xTextWindow)
  57.        { A window where the user can type a list of numbers, then click a button to see the sum, }
  58.        { average and standard deviation of the numbers entered.}
  59.  
  60.             reader: TextReader;   { used to access the numbers typed by the user }
  61.             bttn: myButton;
  62.             sum, average, deviation: extended;
  63.  
  64.             procedure setDefaults;
  65.             override;
  66.             procedure openInRect (title: string;
  67.                                         left, top, right, bottom: integer);
  68.             override;
  69.             procedure doRedraw (badRect: Rect);
  70.             override;
  71.             procedure doKey (ch: char;
  72.                                         modifiers: longint);
  73.             override;
  74.             procedure doClose;
  75.             override;
  76.             procedure doStats;
  77.         end;
  78.  
  79.  
  80.  
  81.  
  82. procedure myButton.HandleClick;
  83.   { when the user clicks on the button, a message is sent to the window to calculate }
  84.   { the statistics. }
  85.     begin
  86.         myWin(itsWindow).doStats
  87.     end;
  88.  
  89. procedure myWin.setDefaults;
  90.     begin
  91.         inherited setDefaults;
  92.         minSize.h := 301;   { set min and max sizes for "growing" window }
  93.         maxSize.h := 301;   { note that window has a fixed horizontal size }
  94.         minSize.v := 150;
  95.         features := features - [hasZoom];  { I have to remove the zoom box because zooming }
  96.                                                             { would not respect the fixed horizontal size. }
  97.         topTextOffset := 50;          { leave room for stuff at the top of the window. }
  98.         vScrollTopOffset := 51;
  99.     end;
  100.  
  101. procedure myWin.openInRect (title: string;
  102.                                 left, top, right, bottom: integer);
  103.     begin
  104.  
  105.         right := left + 300;   { make sure the opening size is the correct fixed horizontal size }
  106.         inherited openInRect(title, left, top, right, bottom);
  107.  
  108.         new(bttn);    { install button that will calculate statistics }
  109.         bttn.setUp(self, 'Stats', 10, 15, 70, 20);
  110.  
  111.         new(reader);    { create a text reader and set it up to read from this window. }
  112.         reader.SetUpFromTextWindow(self);
  113.  
  114.         sum := badReal;        { "badReal" is defined in unit TextReader; used here to indicate "no value" }
  115.         average := badReal;
  116.         deviation := badReal;
  117.  
  118.     end;
  119.  
  120.  
  121. {$PUSH}
  122. {$R-}
  123.  
  124. procedure RealToString (x: extended;
  125.                                 var s: string);
  126.   { useful utility for getting a reasonable up-to-12-character representation of a real number; }
  127.   { doesn't seem to be foolproof, though }
  128.     var
  129.         n, i: integer;
  130.     begin
  131.         if abs(x) <= 1 / badReal then
  132.             s := '0'
  133.         else if abs(x) >= badReal then
  134.             s := '?'
  135.         else if (abs(x) >= 5e8) or (abs(x) < 5e-8) then begin  { exponential form }
  136.                 n := 15;
  137.                 repeat  { this is needed since the stupid computer alllows 4 spaces for the exponent even if it is one two or three digits }
  138.                     s := StringOf(x : n);
  139.                     n := n - 1;
  140.                     i := length(s);
  141.                     while (i > 0) & (s[i] = ' ') do
  142.                         i := i - 1;
  143.                     s[0] := chr(i);
  144.                 until (length(s) <= 12) | (n = 11)
  145.             end
  146.         else begin
  147.                 s := StringOf(x : 1 : 10);
  148.                 i := length(s);
  149.                 while (i > 0) & (s[i] = '0') do   { strip off trailing zeros }
  150.                     i := i - 1;
  151.                 if (i > 0) & (s[i] = '.') then  { strip off terminating decimal point }
  152.                     i := i - 1;
  153.                 if i > 12 then  { maximum length allowed for output is 12}
  154.                     s[0] := chr(12)
  155.                 else
  156.                     s[0] := chr(i);
  157.             end
  158.     end;
  159.  
  160. {$POP}
  161.  
  162.  
  163.  
  164. procedure myWin.doRedraw (badRect: Rect);
  165.     var
  166.         str: string;
  167.     begin
  168.  
  169.         inherited doRedraw(badRect);  { redraws text section of window; also redraws the button }
  170.  
  171.         moveTo(0, 50);        { draw line separating text from button & stats }
  172.         LineTo(theWindow^.portRect.right, 50);
  173.  
  174.         moveTo(100, 12);                                { write out the statistics }
  175.         RealToString(sum, str);
  176.         DrawString(Concat('Sum = ', str));
  177.  
  178.         moveTo(100, 29);
  179.         RealToString(average, str);
  180.         DrawString(Concat('Average = ', str));
  181.  
  182.         moveTo(100, 46);
  183.         RealToString(deviation, str);
  184.         DrawString(Concat('Deviation = ', str));
  185.  
  186.     end;
  187.  
  188.  
  189. procedure myWin.doKey (ch: char;
  190.                                 modifiers: longint);
  191. { The doKey procedure for this window class is modified so that only line feeds and }
  192. { characters that can appear in real numbers are allowed.  Furthermore, any }
  193. { "whitespace" character is converted into a line feed.  Other characters make }
  194. { the computer beep. }
  195.     begin
  196.         if (ch = tab) | (ch = space) | (ch = ',') | (ch = chr(3)) then
  197.             ch := endOfLine;   { endOfLine is defined in UNIT TextReder. }
  198.         if ch in [endOfLine, '0'..'9', '.', 'e', 'E', '+', '-', chr(8), chr($1c)..chr($1f)] then
  199.             inherited doKey(ch, modifiers)
  200.         else
  201.             Sysbeep(1);
  202.     end;
  203.  
  204. procedure myWin.doClose;
  205. { for this simple program, it seemed best to quit when the user closes the }
  206. { unique window used by the program. }
  207.     begin
  208.         halt
  209.     end;
  210.  
  211. procedure myWin.doStats;
  212. { this is called when the user clicks on the button.  It uses the TextReader, reader, }
  213. { to get the numbers that the user has typed in, and calculates the statistics for }
  214. { those numbers. }
  215.     var
  216.         ct: integer;
  217.         total, sqTotal: extended;
  218.         x: extended;
  219.         R: Rect;
  220.     begin
  221.         ct := 0;
  222.         reader.reset;     { start reading from beginning of text in the window }
  223.         reader.skipWhiteSpace;
  224.  
  225.         sum := badReal;
  226.         average := badReal;
  227.         deviation := badReal;
  228.         total := 0;
  229.         sqTotal := 0;
  230.  
  231.         SetPort(theWindow);           { arrange for statistics listed at top of window to be re-written }
  232.         R := theWindow^.portRect;
  233.         R.bottom := 50;
  234.         R.left := 100;
  235.         InvalRect(R);
  236.  
  237.         while reader.moreChars do begin  { get next number and add to totals }
  238.                 ct := ct + 1;
  239.                 reader.ReadReal(x);
  240.                 if reader.numError then begin
  241.                         TellUser('Illegal number found in data.');
  242.                         SetSelectionRange(reader.ErrorPosition, reader.ErrorPosition);
  243.                         ScrollToSelection;
  244.                         EXIT(doStats);
  245.                     end;
  246.                 if not (reader.next in [endOfData, endOfLine]) then begin
  247.                         TellUser('Illegal number found in data.');
  248.                         SetSelectionRange(reader.where, reader.where);
  249.                         ScrollToSelection;
  250.                         EXIT(doStats);
  251.                     end;
  252.                 total := total + x;
  253.                 sqTotal := sqTotal + sqr(x);
  254.                 reader.skipWhiteSpace;
  255.             end;
  256.  
  257.         if ct = 0 then begin
  258.                 TellUser('You haven''t entered any data.');
  259.             end
  260.         else begin  { compute statistics }
  261.                 sum := total;
  262.                 average := sum / ct;
  263.                 deviation := sqrt((sqTotal - sqr(total) / ct) / ct);
  264.             end;
  265.  
  266.     end;
  267.  
  268.  
  269.  
  270.  
  271. procedure OpenAWindow;
  272.     var
  273.         Win: myWin;
  274.     begin
  275.         new(Win);
  276.         Win.open('Basic Statistics');
  277.     end;
  278.  
  279. procedure InitializeApplication;
  280.     begin
  281.         OpenAWindow;
  282.     end;
  283.  
  284. procedure CleanUpApplication;
  285.     begin
  286.     end;
  287.  
  288. procedure UpdateMenus;
  289.     var
  290.         i: integer;
  291.         win: WindowPtr;
  292.     begin
  293.         win := FrontWindow;  { this is the currently active window, or nil if there is none }
  294.         if win = nil then
  295.             DisableItem(fileMenu, 2)
  296.         else
  297.             EnableItem(fileMenu, 2);
  298.     end;
  299.  
  300.  
  301. procedure CloseFrontWindow;
  302.     var
  303.         X: xWindow;
  304.     begin
  305.         if FrontWindow <> nil then
  306.             if window2xWindow(FrontWindow, X) then
  307.                 X.doClose
  308.     end;
  309.  
  310. procedure DoFileMenu (itemNum: integer;
  311.                                 var done: boolean);
  312.     begin
  313.         done := true;  { only command in file menu is Quit! }
  314.     end;
  315.  
  316. procedure DoEditMenu (itemNum: integer);
  317.     begin
  318.     end;
  319.  
  320. procedure DoOtherMenu (menuNum, itemNum: integer);
  321.     begin
  322.     end;
  323.  
  324. procedure ApplicationIdle;
  325.     var
  326.         X: xWindow;
  327.     begin
  328.         if (window2xWindow(FrontWindow, X)) then
  329.             X.idle;
  330.     end;
  331.  
  332. end.